package top.milkbox.common.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 通用工具
 * 创建时间: 2023-12-04 下午 5:38
 *
 * @author milkbox
 */
@Slf4j
public class CommonUtil {

    /**
     * 将集合转换为森林
     *
     * @param sourceList 要转换的集合，集合中的元素必须实现接口CommonUtil.EntityTree
     * @param rootId     以这个值为树的根节点
     * @param <S>        id与parentId的数据类型
     * @param <T>        集合中每个元素的类型
     * @return 返回森林
     * @author 郭泳辰
     */
    public static <S, T extends CommonUtil.EntityTree<S>> List<Tree<S>> toTree(List<T> sourceList, S rootId) {
        // 将OkrNormCategory集合对象转为TreeNode集合对象
        List<TreeNode<S>> treeNodeList = sourceList.stream().map(treeNode -> {
                    if (ObjectUtil.isEmpty(treeNode.getParentId())) {
                        log.warn("当前数据不符合规范，上级id不能为空" + treeNode);
                    }
                    return new TreeNode<>(treeNode.getId(), treeNode.getParentId(),
                            treeNode.getName(), null).setExtra(JSONUtil.parseObj(treeNode));
                }
        ).collect(Collectors.toList());

        // 以parentId等于0作为树的根节点，将TreeNode集合对象构建成为森林
        return TreeUtil.build(treeNodeList, rootId);
    }

    public interface EntityTree<T> {

        T getId();

        T getParentId();

        String getName();
    }

    /**
     * 将森林转换为只包含id的集合
     *
     * @param forest 森林
     * @param <T>    Tree的泛型
     * @return 返回Tree对象的id字段的集合
     * @author 郭泳辰
     */
    public static <T> List<T> forestToIdList(List<Tree<T>> forest) {
        ArrayList<T> resultList = new ArrayList<>();
        generateIdListByDFS(forest, resultList);
        return resultList;
    }

    /**
     * 从指定的数组中根据传递的id查询这个id的所有子级。<br />
     * 此方法为内部方法，不建议直接调用。请使用findAllChildren(......)系列方法
     *
     * @param entityList   被查找的元素集合（集合中的元素必须实现接口CommonUtil.EntityTree）
     * @param id           上级id
     * @param childrenList 结果（集合中的元素必须实现接口CommonUtil.EntityTree）
     * @param deepCount    当前递归深度（从1开始）
     * @param deepLimit    最大递归深度（传递0表示无限制递归深度）
     * @param <S>          集合中id与parentId的类型
     * @param <T>          集合中元素的类型
     * @return 返回子级集合
     */
    private static <S, T extends CommonUtil.EntityTree<S>> List<T> findAllChildrenHelper(
            List<T> entityList, S id, List<T> childrenList, int deepCount, int deepLimit) {
        if (entityList == null || id == null || childrenList == null || (deepLimit != 0 && deepCount > deepLimit)) {
            return childrenList;
        }
        for (T entity : entityList) {
            if (id.equals(entity.getParentId())) {
                childrenList.add(entity);  // 不确定此处如果同时将原集合的元素删除是否会提高效率
                findAllChildrenHelper(entityList, entity.getId(), childrenList, deepCount + 1, deepLimit);
            }
        }
        return childrenList;
    }

    /**
     * 此方法为内部方法，不建议直接调用。请使用findAllChildren(......)系列方法
     */
    private static <S, T extends CommonUtil.EntityTree<S>> List<T> findAllChildrenHelper(
            List<T> entityList, S id, List<T> childrenList, int deepLimit) {
        return findAllChildrenHelper(entityList, id, childrenList, 1, deepLimit);
    }

    /**
     * 从指定的集合（entityList）中找出id的所有子级（包括子级的子级......）。
     *
     * @param entityList 被查找的元素集合（集合中的元素必须实现接口CommonUtil.EntityTree）
     * @param id         上级id
     * @param deepLimit  最大递归深度（传递0表示无限制递归深度）
     * @param <S>        集合中id与parentId的类型
     * @param <T>        集合中元素的类型
     * @return 返回子级集合
     */
    public static <S, T extends CommonUtil.EntityTree<S>> List<T> findAllChildren(
            List<T> entityList, S id, int deepLimit) {
        return findAllChildrenHelper(entityList, id, new ArrayList<>(), deepLimit);
    }

    /**
     * 从指定的集合（entityList）中找出id的所有子级（包括子级的子级......）。<br />
     * 此方法限制递归深度为32层
     *
     * @param entityList 被查找的元素集合（集合中的元素必须实现接口CommonUtil.EntityTree）
     * @param id         上级id
     * @param <S>        集合中id与parentId的类型
     * @param <T>        集合中元素的类型
     * @return 返回子级集合
     */
    public static <S, T extends CommonUtil.EntityTree<S>> List<T> findAllChildren(
            List<T> entityList, S id) {
        return findAllChildrenHelper(entityList, id, new ArrayList<>(), 32);
    }

    /**
     * 深度优先遍历，将森林转换为只包含id的集合
     *
     * @param forest     森林
     * @param resultList 返回结果集合
     * @param <T>        Tree对象的泛型
     * @author 郭泳辰
     */
    private static <T> void generateIdListByDFS(List<Tree<T>> forest, List<T> resultList) {
        forest.forEach(tree -> {
            resultList.add(tree.getId());
            if (ObjectUtil.isNotEmpty(tree.getChildren())) {
                generateIdListByDFS(tree.getChildren(), resultList);
            }
        });
    }


    /**
     * 转为其他类型page，自定义每一项的转换方式
     *
     * @param page      原page
     * @param converter 自定义每一项转换方式
     * @param <T>       目标page类型
     * @param <S>       原page类型
     * @return 返回转换后的page
     * @author 郭泳辰
     */
    public static <T, S> Page<T> convertPage(Page<S> page, Function<S, T> converter) {
        return convertPage(page, page.getRecords().stream().map(converter).collect(Collectors.toList()));
    }

    /**
     * 转为其他类型page，转换方式为BeanUtil.copyToList
     *
     * @param page        原page
     * @param targetClass 转换后目标每一项的类型.class
     * @param <T>         目标page类型
     * @param <S>         原page类型
     * @return 返回转换后的page
     * @author 郭泳辰
     */
    public static <T, S> Page<T> convertPage(Page<S> page, Class<T> targetClass) {
        return convertPage(page, BeanUtil.copyToList(page.getRecords(), targetClass));
    }

    /**
     * 转为其他类型page
     *
     * @param page          原page
     * @param targetRecords 已经转换后的分页数据
     * @param <T>           目标page类型
     * @param <S>           原page类型
     * @return 返回转换后的page
     * @author 郭泳辰
     */
    public static <T, S> Page<T> convertPage(Page<S> page, List<T> targetRecords) {
        Page<T> targetPage = new Page<>();
        targetPage.setRecords(targetRecords);
        targetPage.setTotal(page.getTotal());
        targetPage.setSize(page.getSize());
        targetPage.setCurrent(page.getCurrent());
        targetPage.setOrders(page.orders());
        targetPage.setOptimizeCountSql(page.optimizeCountSql());
        targetPage.setSearchCount(page.searchCount());
        targetPage.setMaxLimit(page.maxLimit());
        targetPage.setCountId(page.countId());
        targetPage.setPages(page.getPages());
        return targetPage;
    }

    /**
     * 将Page&lt;Object&gt;转换为Page&lt;JSONObject&gt;
     *
     * @param page 原始分页对象
     * @param <S>  原始分页对象类型
     * @return 返回JSONObject类型分页对象
     * @author 郭泳辰
     */
    public static <S> Page<JSONObject> toJSONObjects(Page<S> page) {
        return CommonUtil.convertPage(page, JSONUtil::parseObj);
    }


    /**
     * 判断任意简单对象是否为0，如果是0则返回true，否则返回false<br />
     * IllegalArgumentException表示类型不支持，传递null值也会抛出异常
     *
     * @param obj 任意简单对象
     */
    public static boolean isZero(Object obj) {
        if (obj instanceof String) {
            return "0".equals(obj);
        }
        if (obj instanceof Number) {
            Number number = (Number) obj;
            if (number instanceof Integer || number instanceof Long || number instanceof Short || number instanceof Byte) {
                return number.intValue() == 0;
            } else if (number instanceof Double || number instanceof Float) {
                return number.doubleValue() == 0.0;
            }
        }
        if (obj instanceof Character) {
            Character character = (Character) obj;
            return character.equals('0');
        }
        throw new IllegalArgumentException("不支持的类型：" + obj.getClass().getName());
    }


}
